/**
 * 
 */
package com.google.code.netz.wfe.model;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import com.google.code.netz.wfe.api.WorkflowException;

/**
 * @author <a href='mailto:rahul.thakur.xdev@gmail.com'>Rahul Thakur</a>
 * @since 1.0
 * @version $Id$
 */
public abstract class AbstractCase<D> extends AbstractPetriNetEntity<D> implements ICase<D> {

	/**
	 * Transitions that are member of this workflow/case.
	 */
	private List<Transition<?>> transitions = new ArrayList<Transition<?>>();

	/**
	 * Places that are a member of this workflow/case.
	 */
	private List<Place<?>> places = new ArrayList<Place<?>>();

	/**
	 * InputArcs that are a member of this workflow/case.
	 */
	private List<InputArc<?>> inputArcs = new ArrayList<InputArc<?>>();

	/**
	 * OutputArcs that are a member of this workflow/case.
	 */
	private List<OutputArc<?>> outputArcs = new ArrayList<OutputArc<?>>();

	/**
	 * All members of this workflow/case.
	 */
	@SuppressWarnings("unchecked")
	private List allEntities;

	/**
	 * @param label
	 */
	public AbstractCase(String label) {
		super(label);
	}

	/**
	 * Create a ICase with specified label and with specified {@link Place}s,
	 * {@link Transition}s, {@link InputArc}s and {@link OutputArc}s.
	 * <p>
	 * After calling this constructor there is not need to call
	 * {@link #register(IPetriNetEntity)}.
	 * 
	 * @param transitions
	 * @param places
	 * @param inputArcs
	 * @param outputArcs
	 */
	public AbstractCase(String label, List<Transition<?>> transitions, List<Place<?>> places,
			List<InputArc<?>> inputArcs, List<OutputArc<?>> outputArcs) {
		super(label);
		this.transitions = transitions;
		this.places = places;
		this.inputArcs = inputArcs;
		this.outputArcs = outputArcs;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.netz.wfe.model.ICase#getInitialPlace()
	 */
	@Override
	public Place<?> getSource() {
		return this.places.get(0);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.netz.wfe.model.ICase#getSink()
	 */
	@Override
	public Place<?> getSink() {
		return this.places.get(this.places.size() - 1);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.netz.wfe.model.ICase#getInitialTransition()
	 */
	@Override
	public Transition<?> getInitialTransition() {
		if (null != this.transitions && this.transitions.size() > 0)
			return this.transitions.get(0);
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.netz.wfe.model.ICase#getInputArcs()
	 */
	@Override
	public List<InputArc<?>> getInputArcs() {
		return this.inputArcs;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.netz.wfe.model.ICase#getOutputArcs()
	 */
	@Override
	public List<OutputArc<?>> getOutputArcs() {
		return this.outputArcs;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.netz.wfe.model.ICase#getPetriNetEntities()
	 */
	@SuppressWarnings("unchecked")
	@Override
	public List<? extends IPetriNetEntity<?>> getPetriNetEntities() {
		if (null == this.allEntities || this.allEntities.size() == 0) {
			allEntities = new ArrayList();
			allEntities.addAll(this.places);
			allEntities.addAll(this.transitions);
			allEntities.addAll(this.inputArcs);
			allEntities.addAll(this.outputArcs);
		}
		return this.allEntities;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.netz.wfe.model.ICase#getPlaces()
	 */
	@Override
	public List<Place<?>> getPlaces() {
		return this.places;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.netz.wfe.model.ICase#getTransitions()
	 */
	@Override
	public List<Transition<?>> getTransitions() {
		return this.transitions;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.netz.wfe.model.ICase#query(java.lang.Class,
	 * java.util.UUID)
	 */
	@Override
	public <T extends IPetriNetEntity<?>> T query(Class<T> klass, UUID uuid) throws WorkflowException {
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.code.netz.wfe.model.ICase#query(java.lang.Class,
	 * java.lang.String)
	 */
	@Override
	public <T extends IPetriNetEntity<?>> T query(Class<T> klass, String label) throws WorkflowException {
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.google.code.netz.wfe.model.ICase#register(com.google.code.netz.wfe
	 * .model.PetriNetEntity)
	 */
	@Override
	public <T extends IPetriNetEntity<?>> ICase<D> register(T entity) {
		if (entity instanceof Place<?>)
			this.places.add((Place<?>) entity);
		else if (entity instanceof Transition<?>)
			this.transitions.add((Transition<?>) entity);
		else if (entity instanceof InputArc<?>)
			this.inputArcs.add((InputArc<?>) entity);
		else if (entity instanceof OutputArc<?>)
			this.outputArcs.add((OutputArc<?>) entity);
		else {
			// Unknown Petri-Net entity
		}

		return this;
	}

}
